package data;

import SAToDA.Catalogo;
import SAToDA.Curriculo;
import SAToDA.Curso;
import SAToDA.Disciplina;
import SAToDA.Equivalencia;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Classe que realiza a comunicação entre a interface e o Banco de Dados
 *
 * @author LeonardoGabriel/Grupo G2
 */
public class InterfaceBanco {

    //private static final String dbURL = "jdbc:derby://localhost:1527/Satoda";
    //private static final String userName = "grupo2";
    //private static final String password = "12345";
    private static final String dbURL = "jdbc:mysql://143.106.150.216:3306/SatodaDB";
    private static final String userName = "satoda";
    private static final String password = "adotas2014";

    // jdbc Connection
    private static Connection conn = null;
    private static Statement stmt = null;
    private static boolean conectado = false;
    // PADRAO SINGLETON!!
    private static InterfaceBanco single = null;

    final static private Logger logger = LoggerFactory.getLogger(InterfaceBanco.class);

    /**
     * Construtor padrão singleton
     */
    protected InterfaceBanco() {
    }

    /**
     * Construtor padrão singleton, ignora chamada de construcao caso ja existe
     * uma instancia
     *
     * @author Grupo G2
     * @return Retorna a instancia já existente
     */
    public static InterfaceBanco getInterfaceBanco() {
        if (single == null) {
            single = new InterfaceBanco();
        }
        return single;
    }

    /**
     * Funcao de conexão com o banco de dados
     *
     * @author Grupo G2
     * @throws data.DataBaseConnectionException caso ocorra algum erro ao tentar
     * se conectar essa escessão é atirada
     */
    public void conecta() throws DataBaseConnectionException {

        if (conectado) {
            return;
        }

        try {
            //Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            
            conn = DriverManager.getConnection(dbURL, userName, password);
            conectado = true;
            logger.trace("Conexão com o banco de dedos estabelecida!");
        } catch (ClassNotFoundException except) {
            logger.error("A classe org.apache.derby.jdbc.ClientDriver não foi encontrada");
            throw new DataBaseConnectionException();
        } catch (InstantiationException except2) {
            logger.error("A classe org.apache.derby.jdbc.ClientDriver não pode ser instanciada");
            throw new DataBaseConnectionException();
        } catch (IllegalAccessException ex) {
            logger.error("A classe org.apache.derby.jdbc.ClientDriver ou seu construtor não são acessíveis");
            throw new DataBaseConnectionException();
        } catch (SQLException except3) {
            logger.error("Código do erro: " + except3.getErrorCode() + "\nMensagem: " + except3.getMessage() + "\nEstado do SQL: " + except3.getSQLState());
            throw new DataBaseConnectionException();
        }
    }

    /**
     * Dado um curso e 2 anos, retorna uma lista com disciplinas equivalentes
     * entre o primeiro ano e o segundo (cada ano representa um catálogo).
     *
     * @param codCurso Código do curso
     * @param ano1 ano do catálogo 1
     * @param ano2 ano do catálogo 2
     * @return retorna um ArrayList de objetos Equivalência.
     * @throws InternalDataBaseException caso ocorra algum erro na query de
     * busca é atirada essa excessão
     */
    public ArrayList<Equivalencia> getDisciplinasEquivalentes(int codCurso, int ano1, int ano2) throws InternalDataBaseException {
        ArrayList<Equivalencia> equivalencias = new ArrayList<>();
        String query
                = "SELECT D1.id, D1.sigla, D1.nome, D2.id, D2.sigla, "
                + "D2.nome FROM G2_Curriculo C1, G2_Curriculo C2, "
                + "G2_DisciplinaCurriculo DC1, G2_DisciplinaCurriculo DC2, "
                + "G2_Disciplina D1, G2_Disciplina D2, G2_Equivalencia E "
                + "WHERE C1.codCurso = " + codCurso + " AND C2.codCurso = " + codCurso + " AND "
                + "C1.ano = " + ano1 + " AND C2.ano = " + ano2 + " AND "
                + "DC1.idCurriculo = C1.id AND DC2.idCurriculo = C2.id AND "
                + "D1.id = DC1.idDisciplina AND D2.id = DC2.idDisciplina AND "
                + "D1.id = E.disc1 AND D2.id = E.disc2";

        try {
            stmt = conn.createStatement();
            ResultSet res = stmt.executeQuery(query);
            while (res.next()) {
                int id1 = res.getInt(1);
                String sigla1 = res.getString(2);
                String nome1 = res.getString(3);
                int id2 = res.getInt(4);
                String sigla2 = res.getString(5);
                String nome2 = res.getString(6);
                equivalencias.add(new Equivalencia(
                        Disciplina.criaDisciplina(id1, sigla1, nome1),
                        Disciplina.criaDisciplina(id2, sigla2, nome2)));
            }
            res.close();
            stmt.close();
        } catch (SQLException e) {
            logger.error("Código do erro: " + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
            throw new InternalDataBaseException();
        }
        return equivalencias;
    }
    
    public Catalogo getCatalogo(int ano) throws InternalDataBaseException {
        Catalogo catalogo;
        ArrayList<Curso> cursos = new ArrayList<>();
        String query
                = "SELECT C.CODIGO, C.NOME "
                + "FROM G2_Curso C, G2_Curriculo Cu "
                + "WHERE Cu.ANO = " + ano + " AND "
                + "      Cu.CODCURSO = C.CODIGO";

        try {
            stmt = conn.createStatement();
            ResultSet res = stmt.executeQuery(query);
            while (res.next()) {
                int codigoCurso = res.getInt(1);
                String nomeCurso = res.getString(2);
                cursos.add(new Curso(codigoCurso, nomeCurso));
            }
            catalogo = new Catalogo(ano, cursos);
            res.close();
            stmt.close();
        } catch (SQLException e) {
            logger.error("Código do erro: " + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
            throw new InternalDataBaseException();
        }
        return catalogo;
    }

    /**
     * Desconecta do banco de dados
     * @throws DataBaseConnectionException  Caso ocorra um erro ao tentar 
     * desconectar do banco de dados
     */
    public void desconecta() throws DataBaseConnectionException {
        try {
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                DriverManager.getConnection(dbURL + ";shutdown=true");
                conn.close();
            }
            logger.info("Desconectado do banco de dados!");
        } catch (SQLException e) {
            logger.error("Código do erro: " + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
            throw new DataBaseConnectionException();
        }
        conectado = false;
    }
    /*    
     public ArrayList<Curso> getCursos() {
     ArrayList<Curso> c = new ArrayList<>();
     String query = "SELECT codigo, nome FROM APP.Curso";
     try {
     stmt = conn.createStatement();
     ResultSet res = stmt.executeQuery(query);
     while(res.next()) {
     int codigo = res.getInt(1);
     String nome = res.getString(2);
     System.out.println(codigo + ", " + nome);
     c.add(new Curso(codigo, nome));
     }
     res.close();
     stmt.close();
     } catch (SQLException e) {
     logger.error("Código do erro: "  + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
     }
     return c;
     }
    
     /**
     * Faz o query no DB e preenche a lista de curriculos de um dado curso
     * @author Grupo G2
     * @param c Curso cuja lista de curriculos deve ser preenchida
     */
    /*    public void preencheListaCurriculos(Curso c){
     String query = "SELECT Id, ano FROM APP.Curriculo Where Curso = "+String.valueOf(c.getCodigo());
     try {
     stmt = conn.createStatement();
     ResultSet res = stmt.executeQuery(query);
     while(res.next()) {
     int id = res.getInt(1);
     int ano = res.getInt(2);
     System.out.println(id + ", " + ano);
     c.addCurriculo(new Curriculo(c, id, ano));
     }
     res.close();
     stmt.close();
     } catch (SQLException e) {
     logger.error("Código do erro: "  + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
     }
     }
     /**
     * @author Grupo G2
     * Faz o query no DB e preenche a lista de disciplinas de um dado catalogo
     * @param c Curriculo cuja lista de disciplinas deve ser preenchida
     */
    /*    public void preencheListaDisciplinas(Curriculo c) throws InternalDataBaseException{
     String query = "Select D.Id, D.nome, D.sigla from APP.DiscCurr as B, APP.Disciplina as D where "
     + "B.IdCurr = " + String.valueOf(c.getId()) + " and D.Id = B.IdDisc";
     try {
     stmt = conn.createStatement();
     ResultSet res = stmt.executeQuery(query);
     while(res.next()) {
     int id = res.getInt(1);
     String nome = res.getString(2);
     String sigla = res.getString(3);
     System.out.println(sigla + ", " + nome);
     c.addDisciplina(Disciplina.criaDisciplina(id, sigla, nome));
     }
     res.close();
     stmt.close();
     } catch (SQLException e) {
     logger.error("Código do erro: "  + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
     throw new InternalDataBaseException();
     }
     }
    
     /**
     * Procura no banco de dados quais grupos de equivalencia contem a disciplina.
     * @author Grupo G2
     * @param d Disciplina à qual se deseja saber os grupos que contem
     * @return ArrayList de GrupoEquivalencia com grupos que contem
     */
    /*    public ArrayList<GrupoEquivalencia> getGrupos(Disciplina d) {
     String query = "Select D.Id, D.nome, D.sigla from APP.DiscCurr as B, APP.Disciplina as D where "
     + "B.IdCurr = " + String.valueOf(c.getId()) + " and D.Id = B.IdDisc";
     try {
     stmt = conn.createStatement();
     ResultSet res = stmt.executeQuery(query);
     while(res.next()) {
     int id = res.getInt(1);
     String nome = res.getString(2);
     String sigla = res.getString(3);
     System.out.println(sigla + ", " + nome);
     c.addDisciplina(Disciplina.criaDisciplina(id, sigla, nome));
     }
     res.close();
     stmt.close();
     } catch (SQLException e) {
     logger.error("Código do erro: "  + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
     }
     }
     /**
     * Faz query na DB visando conseguir disciplinas equivalentes a selecionada
     * @author Grupo G2
     * @param idDisc Disciplina selecionada
     */
    /*    public void getEquivalente(int idDisc) throws InternalDataBaseException {
     String query = "SELECT d.nome, d.sigla FROM APP.Equivalente e, APP.Disciplina d Where d.Id = e.IdDisc1 and e.IdDisc1 = "+String.valueOf(idDisc);
     try {
     stmt = conn.createStatement();
     ResultSet res = stmt.executeQuery(query);
     while(res.next()) {
     String nome = res.getString(1);
     String sigla = res.getString(2);
     System.out.println(sigla + ", " + nome);
     }
     res.close();
     stmt.close();
     } catch (SQLException e) {
     logger.error("Código do erro: "  + e.getErrorCode() + "\nMensagem: " + e.getMessage() + "\nEstado do SQL: " + e.getSQLState());
     throw new InternalDataBaseException();
     }
     }
    
     /**
     * Desconecta a conexão SQL
     * @author Grupo G2
     */

}
